package com.easylinkin.linkappapi.messagecenter.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.alarm.entity.Alarm;
import com.easylinkin.linkappapi.alarm.mapper.AlarmMapper;
import com.easylinkin.linkappapi.common.service.AppSendMessageService;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.common.utils.message.entity.AppSendMessage.model;
import com.easylinkin.linkappapi.common.utils.message.entity.AppSendMessage.type;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.inspection.entity.ElectricBox;
import com.easylinkin.linkappapi.inspection.service.ElectricBoxService;
import com.easylinkin.linkappapi.messagecenter.dao.MessageCenterMapper;
import com.easylinkin.linkappapi.messagecenter.dto.MessageCenterDto;
import com.easylinkin.linkappapi.messagecenter.entity.MessageCenter;
import com.easylinkin.linkappapi.messagecenter.entity.MessageCenterDetail;
import com.easylinkin.linkappapi.messagecenter.entity.enumType.messageTypeEnum;
import com.easylinkin.linkappapi.messagecenter.entity.vo.MessageCenterVo;
import com.easylinkin.linkappapi.messagecenter.service.MessageCenterDetailService;
import com.easylinkin.linkappapi.messagecenter.service.MessageCenterService;
import com.easylinkin.linkappapi.redis.RedisSync;
import com.easylinkin.linkappapi.ruleengine.entity.RuleEngine;
import com.easylinkin.linkappapi.ruleengine.mapper.RuleEngineMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

/**
 * MessageCenter表服务实现类
 *
 * @author CodeGenerator
 * @date 2022/07/11
 */
@Slf4j
@Service("appMessageCenterService")
public class MessageCenterServiceImpl extends ServiceImpl
        <MessageCenterMapper, MessageCenter> implements MessageCenterService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;
    @Autowired
    private RedissonClient redisson;

    @Resource
    private ElectricBoxService electricBoxService;
    @Resource
    private LinkappUserService linkappUserService;
    @Resource
    private MessageCenterDetailService messageCenterDetailService;
    @Resource
    private RedisSync redisSync;

    @Resource
    private AlarmMapper alarmMapper;

    @Resource
    private DeviceMapper deviceMapper;

    @Resource
    private RuleEngineMapper ruleEngineMapper;

    @Value("${linkapp.runMessageGenerate:true}")
    private Boolean runMessageGenerate;

    @Autowired
    private AppSendMessageService appSendMessageService;


    @Override
    public boolean saveOne(MessageCenter appMessageCenter) {
//        commonService.setCreateAndModifyInfo(appMessageCenter);
//        appMessageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appMessageCenter);
        validRepeat(appMessageCenter);
        validParamFormat(appMessageCenter);
        return save(appMessageCenter);
    }

    /**
     * 每天10点产生配电箱巡检提醒
     */
//    方便测试 将周期改短
//    @Scheduled(cron = "0 0/10 * * * ?")
    @Scheduled(cron = "0 0 10 * * ?")
    public void electricCheckMessageGenSchedule() {
        try {
            log.info("electricCheckMessageGenSchedule定时任务开始执行-------start----------");
            if (!runMessageGenerate) {
                log.info("openReceiving为false,不需要执行定时任务");
                return;
            }
            String key = getLockKey();
//        持有n毫秒
            redisSync.tryAcquireRelease(key, 5 * 60 * 1000, false, () -> {
                //                查询配电箱巡检负责人，根据巡检负责人生成对应消息，owner是巡检负责人
                List<ElectricBox> list = electricBoxService.listUnChecked();
                List<MessageCenterVo> messageCenters = getMessagesWithSingleUser(list);
                List<String> ids = messageCenters.stream().map(MessageCenter::getOwnerId).collect(Collectors.toList());
                log.warn("对用户生成消息：{}", ids);

                for (MessageCenterVo messageCenter : messageCenters) {
                    messageCenter.setType(1);
                    Date d = new Date();
                    messageCenter.setCreateTime(d);
                    messageCenter.setModifyTime(d);
                    messageCenter.setStatus(0);
                    messageCenter.setContent("有您负责的配电箱还未巡检，请尽快完成巡检");
                    messageCenter.setTitle("配电箱巡检提醒");
                    saveOne(messageCenter);
                    List<MessageCenterDetail> details = messageCenter.getMessageCenterDetailList();
                    if (details != null && details.size() > 0) {
                        for (MessageCenterDetail messageCenterDetail : details) {
                            messageCenterDetail.setMessageCenterId(messageCenter.getId());
                            messageCenterDetailService.saveOne(messageCenterDetail);
                        }
                    }
                    // 手机推送
                    if(null != messageCenter.getId()){
                        appSendMessageService
                            .pushMessageToPhone(messageCenter.getId().toString(), model.SECURITY,
                                type.MSG,
                                messageCenter.getOwnerId(),
                                messageCenter.getTitle(), messageCenter.getContent());
                    }
                }
            });
            log.info("electricCheckMessageGenSchedule定时任务完成-------end----------");
        }catch (Exception e){
            log.error("electricCheckMessageGenSchedule定时任务异常-------error----------",e);
        }

    }



    private String getLockKey() {
        //        key = "redis_lock:electricCheckMessageGenSchedule_lock1678789790000_redissync_end";
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        String key = "electricCheckMessageGenSchedule_lock";
        key += calendar.getTime().getTime();
        return key;
    }

    /**
     * 获取可见该消息的user_id: 负责人+管理员+有‘记录查询’菜单权限的角色的人
     * 2022-07-20 最新需求要求为: 对该项目中每一个具备“记录查询”:electricStatistics权限的用户，生成消息通知
     *
     * @param electricBoxes 查询参数
     * @return
     */
    private List<MessageCenterVo> getMessagesWithSingleUser(List<ElectricBox> electricBoxes) {
        List<MessageCenterDetail> messageCenterDetailList = new ArrayList<>();
        for (ElectricBox e : electricBoxes) {
//            (String deviceCode, String deviceTypeName, String position, String leadName, String telephone, Integer messageCenterId) {
            messageCenterDetailList.add(new MessageCenterDetail(e.getCode(), e.getType().toString(), e.getPosition(), e.getLeadId(), e.getTenantId(), e.getLeadName(), e.getTelephone(), null));
        }
        Map<String, List<MessageCenterDetail>> leadIdListMap = messageCenterDetailList.stream().collect(Collectors.groupingBy(MessageCenterDetail::getLeadId));
        Map<String, List<MessageCenterDetail>> tenantIdListMap = messageCenterDetailList.stream().collect(Collectors.groupingBy(MessageCenterDetail::getTenantId));

        List<MessageCenterVo> messageCenterList = new ArrayList<>(16);
        Set<MessageCenterVo> messageCenters = new HashSet<>(16);
        for (ElectricBox electricBox : electricBoxes) {
            String tenantId = electricBox.getTenantId();
//        新结论 管理员不可见
//        负责人的
            if (electricBox != null && electricBox.getLeadId() != null) {
                MessageCenterVo messageCenter = new MessageCenterVo();
                messageCenter.setTenantId(tenantId);
                messageCenter.setOwnerId(electricBox.getLeadId());
                messageCenter.setSelf(true);
                messageCenter.setMessageCenterDetailList(leadIdListMap.get(electricBox.getLeadId()));
                messageCenters.add(messageCenter);
            }
        }
        messageCenterList.addAll(messageCenters);

//        拥有查看角色的
        List<String> tenantIds = electricBoxes.stream().map(ElectricBox::getTenantId).collect(Collectors.toList());
        Set<LinkappUser> users = getUserForRoleCanSeeMessage(tenantIds);
        for (LinkappUser user : users) {
            MessageCenterVo messageCenter = new MessageCenterVo();
            messageCenter.setTenantId(user.getTenantId());
            messageCenter.setOwnerId(String.valueOf(user.getId()));
            messageCenter.setSelf(false);
            messageCenter.setMessageCenterDetailList(tenantIdListMap.get(user.getTenantId()));
            messageCenterList.add(messageCenter);
        }
        return messageCenterList;
    }

    private Set<LinkappUser> getUserForRoleCanSeeMessage(List<String> tenantIds) {
//        硬编码 权限code = inspection 配电箱巡检
        final String PRIVILEGE_CODE = "inspection";
        List<LinkappUser> list = linkappUserService.selectUserByPrivilegeCode(PRIVILEGE_CODE, tenantIds);
        HashSet<LinkappUser> result = new HashSet<>();
        HashSet<String> keys = new HashSet<>();
        for (LinkappUser linkappUser : list) {
            String uniqueFlag = linkappUser.getTenantId() + linkappUser.getId();
            if (!keys.contains(uniqueFlag)) {
                result.add(linkappUser);
                keys.add(uniqueFlag);
            }
        }
        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(MessageCenter appMessageCenter) {
        Assert.notNull(appMessageCenter.getId(), "id不能为空");
        commonService.setModifyInfo(appMessageCenter);
        appMessageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appMessageCenter);
        validParamFormat(appMessageCenter);
        return updateById(appMessageCenter);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatch(List<MessageCenter> appMessageCenters) {
        for (MessageCenter appMessageCenter : appMessageCenters) {
            Assert.notNull(appMessageCenter.getId(), "id不能为空");
            commonService.setModifyInfo(appMessageCenter);
            appMessageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
            validRepeat(appMessageCenter);
            validParamFormat(appMessageCenter);
            updateById(appMessageCenter);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatusBatch(Integer toStatus,Integer type) {
        if (toStatus == null) {
            return false;
        }
//        阅读状态，0-未读，1-已读
        QueryWrapper<MessageCenter> qw = new QueryWrapper<>();
        qw.select("id");
        qw.eq("owner_id", linkappUserContextProducer.getNotNullCurrent().getId());
        if (toStatus.equals(0)) {
            qw.eq("status", 1);
            baseMapper.selectList(qw);
        } else if (toStatus.equals(1)) {
            qw.eq("status", 0);
        }
        if(type!=null){
            qw.eq("type",type);
        }
        List<MessageCenter> list = baseMapper.selectList(qw);
        List<Integer> ids = list.stream().map(MessageCenter::getId).collect(Collectors.toList());
        if (ObjectUtils.isNotEmpty(ids)) {
            UpdateWrapper<MessageCenter> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("status", toStatus);
            updateWrapper.in("id", ids);
            return update(updateWrapper);
        }
        return true;

    }

    @Override
    public int count(MessageCenter messageCenter) {
        messageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        LinkappUser current = linkappUserContextProducer.getNotNullCurrent();
        messageCenter.setOwnerId(String.valueOf(current.getId()));
        return baseMapper.count(messageCenter);
    }

    @Override
    public List<MessageCenterVo> countByType(MessageCenter messageCenter) {
        messageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        LinkappUser current = linkappUserContextProducer.getNotNullCurrent();
        messageCenter.setOwnerId(String.valueOf(current.getId()));
        return baseMapper.countByType(messageCenter);
    }

    @Override
    public void makeMessageCenterMsg(MessageCenterVo msgVo) {
        MessageCenter msg = new MessageCenter();
        BeanUtil.copyProperties(msgVo,msg, CopyOptions.create().setIgnoreNullValue(true));
        saveOne(msg);
        List<MessageCenterDetail> details = msgVo.getMessageCenterDetailList();
        if (details != null && details.size() > 0) {
            for (MessageCenterDetail messageCenterDetail : details) {
                messageCenterDetail.setMessageCenterId(msg.getId());
                messageCenterDetailService.saveOne(messageCenterDetail);
            }
        }
        // 手机推送
        if(null != msg.getId()){
            appSendMessageService.pushMessageToPhone(msg.getId().toString(), model.DEVICE_WARN, type.MSG, msg.getOwnerId(),
                msg.getTitle(), msg.getContent());
        }
    }

    @Override
    public RestMessage findMsgDtoById(Long id) {
        //先查询信息、详情信息
        MessageCenterDto msgDto = this.baseMapper.selectMsgDtoById(id);
        if (msgDto == null){
            return RestBuilders.errorBuilder().message("信息不存在").build();
        }
        //然后再根据信息类型、linkId查询相关数据
        List<MessageCenterDetail> detailList = msgDto.getDetailList();
        Integer msgType = msgDto.getType();
        String linkId = msgDto.getLinkId();
        if (msgType == null || StringUtils.isBlank(linkId)){
            return RestBuilders.successBuilder().data(msgDto).build();
        }
        JSONObject json = JSONUtil.parseObj(msgDto);
        //根据类型查询不同业务数据
        messageTypeEnum msgTypeEnum = messageTypeEnum.getMsgEnum(msgType);
        switch (msgTypeEnum){
            case BOX:
                break;
            case DANGER:
                break;
            case DEVICE_WARN:
                //查询报警信息
                Alarm alarm = alarmMapper.selectById(linkId);
                QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("code",alarm.getDeviceCode());
                queryWrapper.eq("delete_state",1);
                Device device = deviceMapper.selectOne(queryWrapper);

                RuleEngine ruleEngine = ruleEngineMapper.selectById(alarm.getRuleEngineId());
                json.putOpt("device",JSONUtil.parseObj(device));
                json.putOpt("alarm",JSONUtil.parseObj(alarm));
                json.putOpt("rule",JSONUtil.parseObj(ruleEngine));

                break;
            default:
                break;
        }

        //返回数据

        return RestBuilders.successBuilder().data(json).build();
    }

    @Override
    public IPage<MessageCenter> selectPage(Page page, MessageCenter messageCenter) {
        messageCenter.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        LinkappUser current = linkappUserContextProducer.getNotNullCurrent();
        messageCenter.setOwnerId(String.valueOf(current.getId()));
        return baseMapper.selectPage(page, messageCenter);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        return removeByIds(idList);
    }

    @Override
    public void export(MessageCenter appMessageCenter, HttpServletRequest request, HttpServletResponse
            response) {

        IPage<MessageCenter> page = selectPage(new Page(0, -1), appMessageCenter);
        List<MessageCenter> records = page.getRecords();
        List
                <MessageCenterVo> appMessageCenterVos = new ArrayList<>();
        for (MessageCenter expert : records) {
            appMessageCenterVos.add(new MessageCenterVo(expert));
        }

        String keyValue = "标题:title,租户id:tenantId";
        String title = "MessageCenter导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appMessageCenterVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public MessageCenter getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(MessageCenter appMessageCenter) {
//        QueryWrapper<MessageCenter> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("name", appMessageCenter.getName());
//        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
//        List<MessageCenter> list = baseMapper.selectList(queryWrapper);
//        if (list.size() == 0) {
//            return;
//        }
//        if (list.size() > 1) {
//            throw new BusinessException("标题有重复");
//        }
//        if (ObjectUtils.isEmpty(appMessageCenter.getId())) {
//            throw new BusinessException("标题已存在");
//        }
//        if (!appMessageCenter.getId().equals(list.get(0).getId())) {
//            throw new BusinessException("标题已存在");
//        }

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(MessageCenter appMessageCenter) {
        Assert.notNull(appMessageCenter, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(appMessageCenter.getContent()), "内容为空");
        Assert.isTrue(StringUtils.isNotBlank(appMessageCenter.getTitle()), "标题为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(MessageCenter appMessageCenter) {
        Assert.isTrue(appMessageCenter.getTitle() == null || appMessageCenter.getTitle().length() <= 50,
                "标题超长");
    }
}

